/*
	实现Gob类型的编解码
	TODO:
	1. 学习下encoding/xxx中的Decoder、Encoder等
	2. 学习下bufio
*/

package codec

import (
	"bufio"
	"encoding/gob"
	"fmt"
	"io"
)

type GobCodec struct {
	conn io.ReadWriteCloser // TCP或Unix传入的连接
	buf  *bufio.Writer      // 缓冲区，防止阻塞
	enc  *gob.Encoder       // gob编码
	dec  *gob.Decoder       // gob解码
}

// 实现Codec接口

// 确保GobCodec实现了Codec接口
var _ Codec = (*GobCodec)(nil)

// 读取消息头
func (gc *GobCodec) ReadHead(header *Header) error {
	return gc.dec.Decode(header)
}

// 读取消息体
func (gc *GobCodec) ReadBody(body interface{}) error {
	return gc.dec.Decode(body)
}

// 写入消息
func (gc *GobCodec) Write(header *Header, body interface{}) (err error) {
	defer func() {
		_ = gc.buf.Flush()
		if err != nil {
			_ = gc.Close()
		}
	}()

	if err := gc.enc.Encode(header); err != nil {
		fmt.Println("rpc codec: gob error encoding header")
		return err
	}

	if err := gc.enc.Encode(body); err != nil {
		fmt.Println("rpc codec: gob error encoding body")
		return err
	}

	return nil
}

// 关闭
func (gc *GobCodec) Close() error {
	return gc.conn.Close()
}

// 新建GobCodec
func NewGobCodec(conn io.ReadWriteCloser) Codec {
	buf := bufio.NewWriter(conn)
	gc := &GobCodec{
		conn: conn,
		buf:  buf,
		dec:  gob.NewDecoder(conn),
		enc:  gob.NewEncoder(buf),
	}

	return gc
}
